package org.spiderflow.websocket;

import com.alibaba.fastjson.JSON;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.apache.logging.log4j.util.Strings;
import org.spiderflow.core.Spider;
import org.spiderflow.core.utils.SpiderFlowUtils;
import org.spiderflow.model.SpiderWebSocketContext;
import org.spiderflow.model.WebSocketEvent;
import org.spiderflow.model.WsEventType;
import org.spiderflow.model.WsMessage;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * WebSocket通讯编辑服务
 *
 * @author Administrator
 */
@ServerEndpoint("/ws")
@Component
public class WebSocketEditorServer {
    private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(10, 20,
            30, TimeUnit.SECONDS, new LinkedBlockingQueue<>(),
            new ThreadFactoryBuilder().setNameFormat("ws-editor-%d").build());

    private static Spider spider;

    private SpiderWebSocketContext context;

    @OnMessage
    public void onMessage(String message, Session session) {
        WsMessage event = JSON.parseObject(message, WsMessage.class);
        WsEventType eventType = WsEventType.valueOfIgnoreCase(event.getEventType());
        boolean isDebug = eventType == WsEventType.DEBUG;
        if (eventType == WsEventType.TEST || isDebug) {
            context = new SpiderWebSocketContext(session);
            context.setDebug(isDebug);
            context.setRunning(true);
            runTest(event);
        } else if (eventType == WsEventType.STOP && context != null) {
            context.stop();
        } else if (eventType == WsEventType.RESUME && context != null) {
            context.resume();
        }
    }

    private void runTest(WsMessage event) {
        EXECUTOR.execute(() -> {
            String xml = event.getMessage();
            if (!Strings.isEmpty(xml)) {
                spider.runWithTest(SpiderFlowUtils.loadXMLFromString(xml), context);
                context.write(new WebSocketEvent<>(WsEventType.FINISH.getLowCaseType(), null));
            } else {
                context.write(new WebSocketEvent<>(WsEventType.ERROR.getLowCaseType(), "xml不正确！"));
            }
            context.setRunning(false);
        });
    }

    @OnClose
    public void onClose(Session session) {
        context.stop();
    }

    public static void setSpider(Spider spider) {
        WebSocketEditorServer.spider = spider;
    }
}
